<?php

class UploadFile extends CComponent{
    private $arrConfig = array(
        'maxSize' => 20971520, // 上传文件的最大值
        'allowExts' => array('jpg', 'jpeg', 'gif', 'png', 'zip', '7z', 'rar', 'mp3', 'mp4'), // 允许上传的文件后缀 留空不作后缀检查
        'allowTypes' => array(), // 允许上传的文件类型 留空不做检查
        'savePath' => '', // 上传文件保存路径
        'oss' => true,
        'bucket' => 'mmj',

        'thumb' => false, // 使用对上传图片进行缩略图处理
        'thumbMaxWidth' => '', // 缩略图最大宽度
        'thumbMaxHeight' => '', // 缩略图最大高度
        'thumbPrefix' => 'thumb_', // 缩略图前缀
        'thumbSuffix' => '', //后缀
        'thumbPath' => '', // 缩略图保存路径
        'thumbFile' => '', // 缩略图文件名
        'thumbExt' => '', // 缩略图扩展名        
        'thumbRemoveOrigin' => false, // 生成缩略图的时候是否移除原图
        'thumbType' => 2, // 缩略图生成方式 1 按设置大小截取 0 按原图等比例缩略

    );
    private $mixError = array();    //有可能是字符串 有可能是数组，，，确定是哪一个name上传失败则是数组。
    private $arrSuccess = array();

    public function __get($strData) {
        if (isset($this->arrConfig[$strData])) {
            return $this->arrConfig[$strData];
        }
        return null;
    }

    public function __set($strData, $mixData) {
        if (isset($this->arrConfig[$strData])) {
            $this->arrConfig[$strData] = $mixData;
        }
    }

    public function __isset($strData) {
        return isset($this->arrConfig[$strData]);
    }
    /**
     * 架构函数
     * @access public
     * @param array $config  上传参数
     */
    private function __construct($arrConfig = array()) {
        if (is_array($arrConfig)) {
            $this->arrConfig = array_merge($this->arrConfig, $arrConfig);
        }
        $this->savePath = self::defaultSavePath();
        if ($this->oss !== true) {
            $this->savePath = Yii::app()->basePath . '/' . $this->savePath;
        }else{
            require_once Yii::app()->basePath . '/extensions/Oss/sdk.class.php';
        }
    }

    /**
     * 链接上传服务
     * @staticvar null $handier
     * @return \UploadFile
     */
    static public function getInstance($arrConfig = array()) {
        static $handier = NULL;
        if (empty($handier)) {
            $handier = new self($arrConfig);
        }
        return $handier;
    }
    public function getMixError(){
        return $this->mixError;
    }
    public function getOneError(){
        reset($this->mixError);
        $info = current($this->mixError);  
        return $info;
    }
    public function getArrSuccess(){
        return $this->arrSuccess;
    }
    public function getOneSuccess(){
        reset($this->arrSuccess);
        $info = current($this->arrSuccess);
        return  $info;       
    }

    // 自动转换字符集 支持数组转换,把字符串从左右的转为右边的
    private function autoCharset($fContents, $from = 'gbk', $to = 'utf-8') {
        $from = strtoupper($from) == 'UTF8' ? 'utf-8' : $from;
        $to = strtoupper($to) == 'UTF8' ? 'utf-8' : $to;
        if (strtoupper($from) === strtoupper($to) || empty($fContents) || (is_scalar($fContents) && !is_string($fContents))) {
            //如果编码相同或者非字符串标量则不转换
            return $fContents;
        }
        if (function_exists('mb_convert_encoding')) {
            return mb_convert_encoding($fContents, $to, $from);
        } elseif (function_exists('iconv')) {
            return iconv($from, $to, $fContents);
        } else {
            return $fContents;
        }
    }

    /**
     * 检查上传的文件类型是否合法
     * @access private
     * @param string $type 数据
     * @return boolean
     */
    private function checkType($arrFile) {
        if (!empty($this->allowTypes))
            return in_array(strtolower($arrFile['type']), $this->allowTypes);
        return true;
    }

    /**
     * 检查上传的文件后缀是否合法
     * @access private
     * @param string $ext 后缀名
     * @return boolean
     */
    private function checkExt($arrFile) {
        if (!empty($this->allowExts)) {
            $strExt = self::getExt($arrFile['name']);
            return in_array(strtolower($strExt), $this->allowExts, true);
        }
        return true;
    }

    /**
     * 检查文件大小是否合法
     * @access private
     * @param integer $size 数据
     * @return boolean
     */
    private function checkSize($arrFile) {
        return $this->maxSize >= $arrFile['size'];
    }

    /**
     * 检查文件是否非法提交
     * @access private
     * @param string $filename 文件名
     * @return boolean
     */
    private function checkUpload($arrFile) {
        return is_uploaded_file($arrFile['tmp_name']);
    }

    /**
     * 通过文件名取得上传文件的后缀
     * @access public
     * @param string $filename 文件名
     * @return boolean
     */
    public static  function getExt($strFileName) {
        $arrPathinfo = pathinfo($strFileName);
        return $arrPathinfo['extension'];
    }

    /**
     * 检查上传的文件
     * 如果验证通过则返回空
     * 如果验证不通过则返回不通过的原因
     * @access private
     * @param array $arrFile 文件信息
     * 
     * @return boolean
     */
    private function check($arrFile) {
        $strError = '';
        if ($arrFile['error'] !== 0) {
            //文件上传失败
            //捕获错误代码
            $strError = $arrFile['error'];
        }
        //文件上传成功，进行自定义规则检查
        //检查文件大小
        if (!$this->checkSize($arrFile)) {
            $strError = '上传文件大小不符！';
        }

        //检查文件Mime类型
        if (!$this->checkType($arrFile)) {
            $strError = '上传文件MIME类型不允许！';
        }
        //检查文件类型
        if (!$this->checkExt($arrFile)) {
            $strError = '上传文件类型不允许';
        }

        //检查是否合法上传
        if (!$this->checkUpload($arrFile)) {
            $strError = '非法上传文件！';
        }

        return $strError;
    }

    public function upload($strSavePath = '', $strSaveFile = ''){
        //上传先验证，然后再开始上传
        $strSavePath = empty($strSavePath) ? $this->savePath : $strSavePath;

        //看是否要帮忙创建文件夹
        if ($this->oss !== true) {
            if (!is_dir($strSavePath)) {
                // 尝试创建目录
                if (!mkdir($strSavePath, 0777, true)) {
                    $this->error = '上传目录' . $strSavePath . '不存在';
                    return false;
                }
            } else {
                if (!is_writeable($strSavePath)) {
                    $this->error = '上传目录' . $strSavePath . '不可写';
                    return false;
                }
            }
        }

        foreach($_FILES as $strKey => $arrFile){
            $arrFile['ext'] = self::getExt($arrFile['name']);
            $arrFile['savePath'] = $strSavePath;
            $arrFile['saveFile'] = empty($strSaveFile) ? uniqid(). '.' .$arrFile['ext'] : $strSaveFile;
            $arrFile['filename'] = $arrFile['savePath'] . $arrFile['saveFile'];
            if($mixMessage = $this->check($arrFile)){
                $this->mixError[$strKey] = $mixMessage;

            }else{
                // 如果是图像文件 检测文件格式,避免传病毒什么的
                if (in_array(strtolower($arrFile['extension']), array('gif', 'jpg', 'jpeg', 'bmp', 'png', 'swf'))) {
                    $mixInfo = getimagesize($arrFile['tmp_name']);
                    if (false === $mixInfo) {
                        $this->mixError[$strKey] = '非法图像文件';
                        continue;
                    }
                }

                //不是OSS的传输方式
                if ($this->oss !== true){
                    if(move_uploaded_file($arrFile['tmp_name'], $this->autoCharset($arrFile['filename'], 'utf-8', 'gbk'))){
                        $this->mixError[$strKey] = '文件上传保存错误！';
                        continue;
                    }

                    //对图片进行压缩
                    if ($this->oss !== true && $this->thumb && in_array(strtolower($arrFile['extension']), array('gif', 'jpg', 'jpeg', 'bmp', 'png'))) {
                        $this->thumbImg($arrFile);                      
                    }

                }else{
                    if(is_string($mixMessage = $this->ossUpload($arrFile))){
                        $this->mixError[$strKey] = $mixMessage;
                        continue;
                    }
                }
                //保存起来
                $arrData = array(
                    'Path' => $arrFile['filename'],
                    'Size' => $arrFile['size'],
                    'Ext' => $arrFile['ext'],
                    'Type' => $arrFile['type'],
                );
                AttachmentModel::saveData($arrData);
                $this->arrSuccess[$strKey] = $arrFile;
            }
        }
    }

    private function ossUpload($arrFile){
        //oss上传
        $oss_sdk_service = new ALIOSS();
        $oss_sdk_service->set_debug_mode(true);
        $options = array(
            ALIOSS::OSS_CONTENT_TYPE => MimeTypes::get_mimetype(strtolower($arrFile['extension'])),
            ALIOSS::OSS_CONTENT_LENGTH => $arrFile['size'],
        );
        $return = $oss_sdk_service->upload_file_by_file($this->bucket, $arrFile['filename'], $arrFile['tmp_name'], $options);
        if (empty($return->header['_info']['url']) || !isset($return->header['_info']['url'])) {
            return 'OSS上传失败！';
        }       
    }

    private function thumbImg($arrFile){
        //是图像文件生成缩略图
        $thumbWidth = explode(',', $this->thumbMaxWidth);
        $thumbHeight = explode(',', $this->thumbMaxHeight);
        $thumbPrefix = explode(',', $this->thumbPrefix);
        $thumbSuffix = explode(',', $this->thumbSuffix);
        $thumbFile = explode(',', $this->thumbFile);
        $thumbPath = $this->thumbPath ? $this->thumbPath : $arrFile['savepath'];
        $thumbExt = $this->thumbExt ? $this->thumbExt : $arrFile['extension']; //自定义缩略图扩展名
        // 生成图像缩略图
        for ($i = 0, $len = count($thumbWidth); $i < $len; $i++) {
            if (!empty($thumbFile[$i])) {
                $thumbname = $thumbFile[$i];
            } else {
                $prefix = isset($thumbPrefix[$i]) ? $thumbPrefix[$i] : $thumbPrefix[0];
                $suffix = isset($thumbSuffix[$i]) ? $thumbSuffix[$i] : $thumbSuffix[0];
                $thumbname = $prefix . basename($arrFile['filename'], '.' . $arrFile['extension']) . $suffix;
            }
            if (1 == $this->thumbType) {
                Image::thumb2($arrFile['filename'], $thumbPath . $thumbname . '.' . $thumbExt, '', $thumbWidth[$i], $thumbHeight[$i], true);
            } else {
                Image::thumb($arrFile['filename'], $thumbPath . $thumbname . '.' . $thumbExt, '', $thumbWidth[$i], $thumbHeight[$i], true);
            }
        }
        if ($this->thumbRemoveOrigin) {
            // 生成缩略图之后删除原图
            unlink($arrFile['filename']);
        }
    }

    /**
     * 删除图片
     * $strImg 图片路径
     * @return [type] [description]
     */
    public static function deleteImg($strImg){
        require_once Yii::app()->basePath . '/extensions/Oss/sdk.class.php';
        $oss_sdk_service = new ALIOSS();
        $oss_sdk_service->set_debug_mode(true);
        $oss_sdk_service->delete_object(UploadFile::getInstance()->bucket, $strImg);
    }
    /**
     * 默认保存路径
     * @return [type] [description]
     */
    public static function defaultSavePath(){
        return  date('Y') . '/' . date('m') . '/' . date('d') . '/';
    }

}